from math import *
import Image
import ImageTk
import Tkinter
import _chaos

class Box:

    def __init__(self, imagefile, threshold):
        self.image = Image.open(imagefile)
        W, H = self.image.size
        bdry_string = _chaos.boundary(self.image.tostring(), W, H, threshold)
        boundary = Image.fromstring('L', self.image.size, bdry_string)
        if Tkinter._default_root:
            self.window = Tkinter.Toplevel(Tkinter._default_root)
        else:
            self.window = Tkinter.Tk()
        self.window.title('Boundary of %s at threshold %d'%
                          (imagefile, threshold))
        self.canvas = Tkinter.Canvas(self.window, width=W, height=H+20)
        self.canvas.pack()
        self.bitmap = ImageTk.PhotoImage(boundary)
        self.canvas.create_image(0,0, anchor=Tkinter.NW, image=self.bitmap)
        boxcount = _chaos.boxcount(bdry_string, W, H, 255)
        data = []
        for i in range(len(boxcount)):
            try:
                data.append( (-(i+1)*log(2), log(boxcount[i]) ) )
            except OverflowError:
                pass
        self.regression = Regression(300,200,data)
        comment = 'Box dimension is approximately %.3f'%self.regression.a
        self.canvas.create_text(20, H+6, anchor=Tkinter.NW,
                                text=comment)

class Regression:

    def __init__(self, width, height, data):
        self.width, self.height = width, height
        self.x_min, self.x_max, self.y_min, self.y_max = 0,0,0,0
        for datum in data:
            x, y = datum
            self.x_min = min(self.x_min, x)
            self.x_max = max(self.x_max, x)
            self.y_min = min(self.y_min, y)
            self.y_max = max(self.y_max, y)
        try:
            self.x_scale = (self.width - 20)/(self.x_max - self.x_min)
        except ZeroDivision:
            self.x_scale = 1.0
        try:
            self.y_scale = (self.height - 20)/(self.y_max - self.y_min)
        except ZeroDivision:
            self.y_scale = 1.0
        if Tkinter._default_root:
            self.window = Tkinter.Toplevel(Tkinter._default_root)
        else:
            self.window = Tkinter.Tk()
        self.window.title('Least squares regression')
        self.canvas = Tkinter.Canvas(self.window,
                                     width=self.width, height=self.height)
        self.canvas.pack()
        points = []
        self.dots = []
        for datum in data:
            x, y = self.pixels(datum[0],datum[1])
            self.dots.append(self.canvas.create_oval(x-2, y-2, x+2, y+2,
                                                     fill='red'))
            points += [x,y]
        self.graph = self.canvas.create_line(*points)
        self.a, self.b = self.least_squares(data)
        X0, Y0 = self.pixels(data[0][0], self.a*data[0][0]+self.b)
        Xn, Yn = self.pixels(data[-1][0], self.a*data[-1][0]+self.b)
        self.line = self.canvas.create_line(X0,Y0,Xn,Yn, fill='blue')
        comment = 'Least squares slope is approximately %.3f'%self.a
        self.canvas.create_text(20, self.height-14, fill='blue',
                                anchor=Tkinter.NW, text=comment)
        
    def pixels(self, x, y):
        return  [int(10+(x - self.x_min)*self.x_scale),
                 int(10+(self.y_max - y)*self.y_scale)]

        
    def least_squares(self, data):
        X, Y, XY, XX = 0.0, 0.0, 0.0, 0.0
        n = float(len(data))
        for point in data:
            x, y = point
            X += x
            Y += y
            XY += x*y
            XX += x*x
        a = (n*XY - X*Y)/(n*XX - X*X)
        b = (XX*Y - X*XY)/(n*XX - X*X)
        return (a,b)

